Composition Functions

This is a beta feature.

This feature was introduced in v1.11.
This feature graduated to beta status in v1.14.

For more information read the Crossplane feature lifecycle.

Composition 函数(简称函数)是模板化 crossplane 资源的自定义程序。 在创建复合资源(XR)时,crossplane 会调用 composition 函数来决定应创建哪些资源。 你可以使用 Go 或 Python 等通用编程语言编写函数来模板化资源。 使用通用编程语言可以让函数使用更高级的逻辑来模板化资源,如循环和条件。

您可以使用 Go 或 Python 等通用编程语言构建一个函数。 crossplane 社区还构建了一些函数,让您使用 CUE、类似 helm 的 Go 模板Patch and Transforms.

安装 Composition 功能

安装功能会创建一个功能 pod。 Crossplane 会向该 pod 发送请求,询问它在创建 Composition 资源时要创建哪些资源。

使用crossplane安装功能功能对象设置spec.packages值为功能包的位置。

例如,安装 Function Patch and Transform

1apiVersion: pkg.crossplane.io/v1beta1
2kind: Function
3metadata:
4  name: function-patch-and-transform
5spec:
6  package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
Tip
函数是 crossplane 软件包,有关软件包的更多信息,请参阅软件包文档.

默认情况下,Function pod 安装在与 crossplane 相同的 namespace (crossplane-system)。

验证一个 Composition 函数

使用 kubectl get functions 查看函数的状态

在安装过程中,函数将 INSTALLED 报告为 True,将 HEALTHY 报告为 Unknown

1kubectl get functions
2NAME INSTALLED HEALTHY PACKAGE AGE
3function-patch-and-transform True Unknown xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4 10s

功能安装完成并被引用后,“HEALTHY “状态将报告为 “True”。

在 Composition 中被引用函数

当你创建一个复合资源时,crossplane 会调用一个 Function 来确定它应该创建哪些资源;当你更新或删除一个复合资源时,该 Function 还会告诉 crossplane 如何处理这些资源。

当 crossplane 调用函数时,它会将复合资源的当前状态发送给函数,同时也会将复合资源拥有的任何托管资源的当前状态发送给函数。

crossplane 通过查看复合资源所引用的 Composition,知道当复合资源发生变化时应调用哪个 Function。

crossplane 有四个核心组件,用户通常会把它们混为一谈:

  • Composition - 用于定义如何创建资源的模板。
  • 复合资源定义 (XRD) - 一种自定义 API 规范。
  • 复合资源 (XR) - 使用 CompositeResourceDefinition 中定义的自定义 API 创建。XRs 使用 Composition 模板来创建新的托管资源。
  • 声明 (XRC) - 类似于 Composite Resource,但具有名称空间范围。

要使用composition功能,请设置composition模式Pipelines.

定义一个 Pipelines步骤。每个步骤都会调用一个函数。

每个 步骤被引用一个函数来引用名称的名称。

Important

被引用的composition 模式: Pipelines不能使用 resources 字段指定资源模板。

使用功能 “修补和转换 “创建资源模板。

某些函数还允许您指定一个输入。函数定义了输入输入。

本例使用 功能修补和转换。 功能修补和转换实现了 crossplane 资源模板。 输入类型为 资源,并接受 Patch and Transform资源作为输入。

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3# Removed for Brevity
 4spec:
 5  # Removed for Brevity
 6  mode: Pipeline
 7  pipeline:
 8  - step: patch-and-transform
 9    functionRef:
10      name: function-patch-and-transform
11    input:
12      apiVersion: pt.fn.crossplane.io/v1beta1
13      kind: Resources
14      resources:
15      - name: storage-bucket
16        base:
17          apiVersion: s3.aws.upbound.io/v1beta1
18          kind: Bucket
19          spec:
20            forProvider:
21              region: "us-east-2"

在 Composition 中被引用函数的 Pipelines

当复合资源发生变化时,Crossplane 可以询问一个以上的 Function 做什么。 当一个 Composition 有两个或更多步骤的流水线时,Crossplane 会调用所有步骤。 它会按照它们在流水线中出现的顺序调用它们。

Crossplane 将前一个函数的结果传递给流水线中的每一个函数,从而实现了强大的函数组合。 在这个例子中,Crossplane 调用了 函数-提示创建一个 S3 存储桶,然后将该存储桶传递给函数-自动就绪,当桶就绪时,它会将 Composition 资源标记为就绪。

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3# Removed for Brevity
 4spec:
 5  # Removed for Brevity
 6  mode: Pipeline
 7  pipeline:
 8  - step: cue-export-resources
 9    functionRef:
10      name: function-cue
11    input:
12      apiVersion: cue.fn.crossplane.io/v1beta1
13      kind: CUEInput
14      name: storage-bucket
15      export:
16        target: Resources
17        value: |
18          apiVersion: "s3.aws.upbound.io/v1beta1"
19          kind: "Bucket"
20          spec: forProvider: region: "us-east-2"          
21  - step: automatically-detect-readiness
22    functionRef:
23      name: function-auto-ready

测试被引用函数的 Composition

你可以使用 Crossplane CLI 预览任何使用 Composition 函数的 Composition 的 Output。 你不需要 Crossplane 控制平面就可以做到这一点。 Crossplane CLI 使用 Docker Engine 来运行函数。

Tip
请参阅 Crossplane CLI docs 了解如何安装和被引用 crossplane CLI。
Important
运行 crossplane beta render 需要 Docker

提供composition资源、composition和composition函数,以便在本地渲染输出。

1crossplane beta render xr.yaml composition.yaml functions.yaml

crossplane beta render 将资源以 YAML 格式打印到 stdout。 它首先打印 Composition 资源,然后打印组合函数创建的资源。

 1---
 2apiVersion: example.crossplane.io/v1
 3kind: XBucket
 4metadata:
 5  name: example-render
 6---
 7apiVersion: s3.aws.upbound.io/v1beta1
 8kind: Bucket
 9metadata:
10  annotations:
11    crossplane.io/composition-resource-name: storage-bucket
12  generateName: example-render-
13  labels:
14    crossplane.io/composite: example-render
15  ownerReferences:
16  - apiVersion: example.crossplane.io/v1
17    blockOwnerDeletion: true
18    controller: true
19    kind: XBucket
20    name: example-render
21    uid: ""
22spec:
23  forProvider:
24    region: us-east-2

您可以使用这些文件,通过运行 crossplane beta render 重现下面的输出结果。

XR.yaml` 文件包含要渲染的 Composition 资源:

1apiVersion: example.crossplane.io/v1
2kind: XBucket
3metadata:
4  name: example-render
5spec:
6  bucketRegion: us-east-2

composition.yaml` 文件包含用于渲染复合资源的 Composition:

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3metadata:
 4  name: example-render
 5spec:
 6  compositeTypeRef:
 7    apiVersion: example.crossplane.io/v1
 8    kind: XBucket
 9  mode: Pipeline
10  pipeline:
11  - step: patch-and-transform
12    functionRef:
13      name: function-patch-and-transform
14    input:
15      apiVersion: pt.fn.crossplane.io/v1beta1
16      kind: Resources
17      resources:
18      - name: storage-bucket
19        base:
20          apiVersion: s3.aws.upbound.io/v1beta1
21          kind: Bucket
22        patches:
23        - type: FromCompositeFieldPath
24          fromFieldPath: spec.bucketRegion
25          toFieldPath: spec.forProvider.region

functions.yaml` 文件包含 Composition 在其 Pipelines 步骤中引用的函数:

1---
2apiVersion: pkg.crossplane.io/v1beta1
3kind: Function
4metadata:
5  name: function-patch-and-transform
6spec:
7  package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4

Crossplane CLI 使用 Docker Engine 来运行函数。 你可以通过在 functions.yaml 中添加注解来改变 Crossplane CLI 运行函数的方式。 在函数中添加 render.crossplane.io/runtime 注解来改变函数的运行方式。

crossplane beta render 支持两个 render.crossplane.io/runtime 值:

  • Docker(默认)连接到 Docker 引擎。它使用 docker 拉取并运行函数运行时。
  • 开发 “连接到手动运行的函数运行时。

当您被引用到 开发运行时,crossplane CLI 会忽略函数的 packages。相反,它希望你确保函数监听的是 localhost 端口 9443。 函数监听时必须不使用 gRPC 传输安全机制。 大多数函数 SDK 都允许你使用 --insecure flag 运行函数,以禁用传输安全机制。 例如,你可以使用 go run . --insecure 在本地运行 Go 函数。

1apiVersion: pkg.crossplane.io/v1beta1
2kind: Function
3metadata:
4  name: function-patch-and-transform
5  annotation:
6    render.crossplane.io/runtime: Development
7spec:
8  package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
Tip
编写 Composition 函数时,使用 “开发 “运行时来端到端测试您的函数。

crossplane beta render 还支持以下函数注解。 这些注解会影响它运行函数的方式:

  • render.crossplane.io/runtime-docker-cleanup - 当使用 Docker

runtime 这个注解指定 CLI 在调用函数后是否应停止函数容器。 它支持的 Values 有Stop(停止容器)和Orphan(让容器继续运行)。

  • render.crossplane.io/runtime-docker-pull-policy - 当使用 Docker 运行时时,该注解指定 CLI 应在何时拉取函数的 package。它支持 Values AlwaysNeverIfNotPresent
  • render.crossplane.io/runtime-development-target - 当使用 Development 运行时,该注解会告诉 CLI 连接到在指定目标运行的 Function。它被引用gRPC 目标语法

写一个 Composition 函数

Composition 函数可让您用自己选择的编程语言编写的代码取代复杂的 Composition。 Crossplane 提供各种工具、软件开发工具包(SDK)和模板,帮助您编写函数。

下面是一个小巧的 hello world 函数示例。这个示例是用 Go 编写的。

1func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequest) (*fnv1beta1.RunFunctionResponse, error) {
2        rsp := response.To(req, response.DefaultTTL)
3        response.Normal(rsp, "Hello world!")
4        return rsp, nil
5}

有些人设计的 Composition 功能可以被任何类型的composition资源引用。Function Patch and TransformFunction Auto Ready可以被任何类型的composition资源引用。

另一种常见的模式是为一种复合资源编写一个特定的 Composition 函数。 该函数包含在创建复合资源时告诉 crossplane 要创建哪些资源所需的所有逻辑。 当你编写这样的 Composition 函数时,你的 Composition 可以很小。 它只是告诉 crossplane 在你创建、更新或删除复合资源时要运行什么函数。

该 Composition 命令 crossplane 调用 function-xr-xbucket函数。 XBucketfunction-xr-xbucket “是硬编码,用于处理 “XBucket “复合资源。

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3metadata:
 4  name: example-bucket-function
 5spec:
 6  compositeTypeRef:
 7    apiVersion: example.crossplane.io/v1
 8    kind: XBucket
 9  mode: Pipeline
10  pipeline:
11  - step: handle-xbucket-xr
12    functionRef:
13      name: function-xr-xbucket

要写好 Composition 函数,你:

1.从模板中创建函数。 2.编辑模板,添加函数逻辑。 3.测试函数。 4.构建函数,并将其推送到 packages 注册表。

您可以使用 Crossplane CLI来创建、测试、构建和推送函数。 例如

 1# Create the function from a template.
 2crossplane beta xpkg init function-example function-template-go
 3Initialized package "function-example" in directory "/home/negz/control/negz/function-example" from https://github.com/crossplane/function-template-go/tree/91a1a5eed21964ff98966d72cc6db6f089ad63f4 (main)
 4
 5$ ls
 6Dockerfile fn.go fn_test.go go.mod go.sum input LICENSE main.go package README.md renovate.json
 7
 8# Edit the template to add your function's logic
 9$ vim fn.go
10
11# Build the function.
12$ docker build . --quiet --tag runtime
13sha256:2c31b0f7a34b34ba5b0b2dacc94c360d18aca1b99f56ca4f40a1f26535a7c1c4
14
15# Package the function.
16$ crossplane xpkg build -f package --embed-runtime-image=runtime
17
18# Test the function.
19$ go run . --insecure
20$ crossplane beta render xr.yaml composition.yaml functions.yaml
21
22# Push the function package to xpkg.upbound.io.
23$ crossplane xpkg push -f package/*.xpkg crossplane-contrib/function-example:v0.1.0
Tip
crossplane 有[特定语言指南](https://crossplane.devops.gold/knowledge-base/guides/更详细的函数编写指南,请参考您首选语言的指南。

在编写 Composition 函数时,了解 Composition 函数的工作原理是非常有用的。 请阅读下一节内容,了解Composition 函数的工作原理

Composition 函数如何工作

每个 Composition 函数实际上都是一个gRPC 服务器。gRPC 是一个高性能、开源的远程过程调用(RPC)框架。当你安装一个函数 时,crossplane 会将该函数部署为 gRPC 服务器。 Crossplane 会对所有 gRPC 通信进行加密和验证。

你不必成为 gRPC 专家也能编写函数。 Crossplane 的函数 SDK 会为你设置 gRPC。 不过,了解 Crossplane 如何调用你的函数,以及你的函数应该如何响应是很有用的。

sequenceDiagram
    User->>+API Server: Create composite resource
    Crossplane Pod->>+API Server: Observe composite resource
    Crossplane Pod->>+Function Pod: gRPC RunFunctionRequest
    Function Pod->>+Crossplane Pod: gRPC RunFunctionResponse
    Crossplane Pod->>+API Server: Apply desired composed resources

当您创建、更新或删除使用 Composition 函数的复合资源时,crossplane 会按照这些函数在 Composition 管道中出现的顺序调用它们。 Crossplane 通过向每个函数发送 gRPC RunFunctionRequest 来调用它们。 该函数必须以 gRPC RunFunctionResponse 进行响应。

Tip
您可以在 Buf Schema Registry 中找到 RunFunctionRequest 和 RunFunctionResponse RPC 的详细模式。

当 crossplane 调用函数时,它会在 RunFunctionRequest 中包含四项重要内容。

1.Composition 资源和任何composition资源的观测状态。 2.复合资源和任何composition资源的期望状态。 3.函数的输入。 4.函数 Pipelines 的上下文

函数的主要工作是更新期望状态并将其返回给 crossplane。 它通过返回 RunFunctionResponse 来实现这一目标。

大多数 Composition 函数都会读取所观察到的复合资源状态,并利用它将composition资源添加到所需状态。 这就告诉了 crossplane 它应该创建或更新哪些composition资源。

Tip

Composition 资源是由复合资源创建的资源。 复合资源通常是 crossplane 受管资源(MR),但也可以是任何类型的 crossplane 资源。 例如,复合资源也可以创建 ProviderConfig 或其他类型的复合资源。

观察到的状态

当你创建像这样的 Composition 资源时,crossplane 会观察到它,并将其作为观察状态的一部分发送给 Composition 函数。

1apiVersion: example.crossplane.io/v1
2kind: XBucket
3metadata:
4  name: example-render
5spec:
6  bucketRegion: us-east-2

如果已经存在任何composition资源,crossplane 会对其进行观察,并将其作为观察状态的一部分发送给您的函数。

crossplane 还会观察您的 Composition 资源和任何composition资源的连接详情,并将其作为观察状态的一部分发送给您的函数。

Crossplane 在开始调用 Pipelines 中的函数之前,会对 Composition 资源和任何composition资源进行一次观测。 这意味着,Crossplane 会向 Pipelines 中的每个函数发送相同的观测状态。

期望状态

期望状态是函数 Pipelines 希望对 Composition 资源和任何composition资源进行更改的集合。 当函数将composition资源添加到期望状态时,crossplane 就会创建这些资源。

功能可以改变:

  • Composition 资源的 “状态”。
  • 任何composition资源的 “元数据 “和 “规格”。

函数还可以更改 Composition 资源的连接详情和就绪状态。 函数通过告诉 Crossplane 其composition资源是否就绪来表明 Composition 资源已就绪。 当函数管道告诉 Crossplane 所有composition资源都已就绪时,Crossplane 就会将 Composition 资源标记为就绪。

函数不能改变:

  • composition资源的 metadataspec
  • 任何composition资源的 “状态”。
  • 任何composition资源的连接详情。

一个由多个函数composition的流水线会积累所需的状态,这意味着每个函数都是建立在流水线中之前函数的所需状态之上。 Crossplane 会向一个函数发送流水线中之前所有函数积累的所需状态。 该函数会添加或更新所需的状态,然后将其传递下去。 当流水线中的最后一个函数运行完毕后,Crossplane 就会应用其返回的所需状态。

Important

函数必须将其 RunFunctionRequest 中的所有所需状态复制到其 RunFunctionResponse 中。 如果函数在其所需状态中添加了资源,则下一个函数必须将其复制到所需的状态中。 如果没有,则 crossplane 不会应用该资源。 如果该资源存在,则 crossplane 会将其删除。

函数可以有意选择不复制所需的部分状态,例如,函数可以选择不复制所需的资源,以防止该资源的存在。

大多数功能 SDK 都会自动复制所需的状态。

函数只应将它所关心的字段添加到所需的状态中。 每次 crossplane 调用它时,它都应添加这些字段。 如果函数将某个字段添加到所需的状态中一次,但在下次调用时没有添加,则 crossplane 会删除该字段。 composition资源也是如此。 如果函数将某个composition资源添加到所需的状态中,但在下次调用时没有添加,则 crossplane 会删除该composition资源。

Tip
crossplane 使用服务器端引用来引用函数 Pipelines 返回的所需状态。在服务器端引用术语中,所需的状态是_完全指定的意图_。

例如,如果函数只想确保区域 us-east-2 中的 S3 bucket 存在,它就应该将此资源添加到所需的composition资源中。

1apiVersion: s3.aws.upbound.io/v1beta1
2kind: Bucket
3spec:
4  forProvider:
5    region: us-east-2

即使 Bucket 已经存在,并且有其他 spec 字段,或者有 status, name, labels 等字段,函数也应该省略它们。 函数应该只包含它有意见的字段。 crossplane 会应用函数关心的字段,将它们与现有的 Bucket 合并。

Tip
Composition 功能实际上并不使用 YAML 来引用所需的和观察到的资源。 本例使用 YAML 仅为说明目的。

功能输入

如果 Composition 包括 输入输入是为函数提供额外配置的有用方法。 支持输入是可选的,并非所有函数都支持输入。

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3metadata:
 4  name: example-render
 5spec:
 6  compositeTypeRef:
 7    apiVersion: example.crossplane.io/v1
 8    kind: XBucket
 9  mode: Pipeline
10  pipeline:
11  - step: patch-and-transform
12    functionRef:
13      name: function-patch-and-transform
14    input:
15      apiVersion: pt.fn.crossplane.io/v1beta1
16      kind: Resources
17      resources:
18      - name: storage-bucket
19        base:
20          apiVersion: s3.aws.upbound.io/v1beta1
21          kind: Bucket
22        patches:
23        - type: FromCompositeFieldPath
24          fromFieldPath: spec.bucketRegion
25          toFieldPath: spec.forProvider.region
Important
crossplane 不会验证函数的输入,因此函数最好验证自己的输入。

功能 Pipelines 上下文

有时,Pipelines 中的两个函数希望彼此共享非所需状态的信息。 为此,函数可以使用上下文。 任何函数都可以写入 Pipeline 上下文。 Crossplane 会将上下文传递给所有后续函数。 当 Crossplane 调用完所有函数后,它会丢弃 Pipeline 上下文。

Crossplane 也可以写入上下文。 如果启用 alpha composition environment 功能,crossplane 就会将环境写入顶级上下文字段 apiextensions.crossplane.io/environment

关闭composition功能

Crossplane 默认启用 Composition 函数。 使用 helm install --args 在 Crossplane 中禁用 beta 功能标志,即可禁用对 Composition 函数的支持。

1helm install crossplane --namespace crossplane-system crossplane-stable/crossplane \
2    --create-namespace \
3    --set "args='{--enable-composition-functions=false}'"

前面的 Helm 命令在安装 crossplane 时禁用了 Composition 功能特性标志。 通过查找日志行确认是否禁用了 Composition 功能:

1kubectl -n crossplane-system logs -l app=crossplane
2{"level":"info","ts":1674535093.36186,"logger":"crossplane","msg":"Beta feature enabled","flag":"EnableBetaCompositionFunctions"}

如果在 crossplane 启动时没有看到日志行,则表示已禁用了 Composition 功能。